using System;
using SharpMud.Net.Telnet.IAC;

namespace SharpMud.Net.Telnet.Session.NegotationAgents
{
	/// <summary>
	/// This is the negotiation daemon for enabling/disabling MXP usage.
	/// Just for negotiation. Got that? Nothing else!
	/// Parsing layers must tie into this daemon's events in order to determine what to do.
	/// </summary>
	public class MXP : IFeatureNegotiationAgent
	{
		private TelnetSessionBase _HostSession;
		private bool _Enabled;
		private int _ChangesPending;
		private bool _RequireClientVerification;
		private bool _AutoStart;
		private bool _IsStarted;
		private SharpMud.Net.Telnet.Session.FeatureNegotiationBehavior _Behavior;

		#region Constructors
		private MXP()
		{
		}
		public MXP(TelnetSessionBase hostSession)
		{
			_Behavior = (FeatureNegotiationBehavior)(-1);

			_Enabled = false;
			_IsStarted = false;
			_AutoStart = true;
			_ChangesPending = 0;
			_HostSession = hostSession;
			_RequireClientVerification = false;
			_HostSession.IAC.In.IAC_Feature_Negotiation +=new SharpMud.Net.Telnet.Session.DataProcessors.IAC.IACInputEventHandler(IAC_Feature_Negotiation);
		}
		#endregion

		#region Public Properties

		public bool ChangePending
		{
			get
			{
				return (_ChangesPending>0);
			}
		}
		/// <summary>
		/// Whether or not this daemon has given the final word that the server will
		/// be using MXP.
		/// </summary>
		public bool IsStarted
		{
			get
			{
				if(!_Enabled)
					return false;
				else
					return _IsStarted;
			}
			set
			{
				if(_IsStarted && value==false)
				{
					throw new InvalidOperationException();
				}
				if(!_IsStarted && value==true)
				{
					_StartMXP();
				}
			}
		}
		/// <summary>
		/// Whether or not this daemon should tell the client that yes, after all, it will be 
		/// using MXP.
		/// </summary>
		public bool AutoStart
		{
			get
			{
				return _AutoStart;
			}
			set
			{
				if(_AutoStart!=value)
				{
					_AutoStart = value;
					if(value==true && _Enabled==true && _IsStarted==false)
					{
						_StartMXP();
					}
				}
			}
		}
		#endregion
		#region Event Handlers
		private void IAC_Feature_Negotiation(SharpMud.Net.Telnet.Session.DataProcessors.IAC.InputLayer sender, SharpMud.Net.Telnet.Session.DataProcessors.IAC.IACInputEventArgs e)
		{
			System.Diagnostics.Debug.WriteLine(
				String.Format(
					"Incoming_IAC_Feature_Negotiation Type={0}:{1} Query={2}:{3}"
				,e.FeatureType.Name,e.FeatureType.Value,e.NegotiationQuery.Name,e.NegotiationQuery.Value)
				,"Net.Telnet.Agents.MXP");
			if(e.FeatureType!=ControlCodes.TELOPT.MXP) return;
			
			if(e.NegotiationQuery == ControlCodes.WILL)
			{
				//The client is saying it wants us to accept its MXP.
				//Thats not how we run things around here.
				//_HostSession.IAC.Out.Send_FeatureNegotiation_Packet(ControlCodes.DONT,ControlCodes.TELOPT.MXP);
				return;
			}
			if(e.NegotiationQuery == ControlCodes.WONT)
			{
				//The client is saying it doesn't want us to accept its MXP.
				//Thats not how we run things around here.
				//_HostSession.IAC.Out.Send_FeatureNegotiation_Packet(ControlCodes.DONT,ControlCodes.TELOPT.MXP);
				return;
			}
			if(e.NegotiationQuery == ControlCodes.DO)
			{
				if(!_Enabled)
				{
					_Enabled = true;
					_IsStarted = false;
				}
				if(ChangePending)
					_ChangesPending--;
				if(AutoStart)
					this.IsStarted = true;
				return;
			}
			if(e.NegotiationQuery == ControlCodes.DONT)
			{
				if(_Enabled)
				{
					if(_IsStarted)
					{
						_IsStarted = false;
					}
					_Enabled = false;
				}
				if(ChangePending)
					_ChangesPending--;
				return;
			}
		}
		#endregion


		#region IFeatureNegotiationAgent Members

		public SharpMud.Net.Telnet.Session.FeatureNegotiationBehavior Behavior
		{
			get
			{
				return _Behavior;
			}
			set
			{
				if(value==FeatureNegotiationBehavior.DemandClientSupport && this.Status!=TriState.True)
				{
					this.TurnFeatureOn();
				}
				if(value==FeatureNegotiationBehavior.RejectClientOnDemand && this.Status!=TriState.False)
				{
					this.TurnFeatureOff();
				}
				if(value==FeatureNegotiationBehavior.AcceptClientOnDemand && this.Status!=TriState.False)
				{
					this.TurnFeatureOn();
				}
				_Behavior = value;
			}
		}

		public System.TriState Status
		{
			get
			{
				if(this._RequireClientVerification && this._ChangesPending>0)
					return TriState.UseDefault;
				if(this._Enabled)
					return TriState.True;
				else
					return TriState.False;
			}
		}

		public bool EffectiveStatus
		{
			get
			{
				return this._Enabled;
			}
		}

		public void TurnFeatureOn()
		{
			if(_Enabled==false /*&& (ChangePending==false || _RequireClientVerification==false)*/)
			{
				//Need to turn remote MXP support back on
				_ChangesPending++;
				this._HostSession.IAC.Out.Send_FeatureNegotiation_Packet(ControlCodes.WILL,ControlCodes.TELOPT.MXP);
				if(!_RequireClientVerification)
				{
					_Enabled = true;
				}
				return;
			}
		}

		public void TurnFeatureOff()
		{
			if(_Enabled==true /*&& (ChangePending==false || _RequireClientVerification==false)*/)
			{
				//Need to turn remote MXP support off
				_ChangesPending++;
				this._HostSession.IAC.Out.Send_FeatureNegotiation_Packet(ControlCodes.WONT,ControlCodes.TELOPT.MXP);
				_IsStarted = false;
				if(!_RequireClientVerification)
				{
					_Enabled = false;
				}
				return;
			}
		}

		#endregion

		private void _StartMXP()
		{
			_HostSession.IAC.Out.Send_Subrequest_Packet(ControlCodes.TELOPT.MXP,new byte[] {});
			_IsStarted = true;
			_HostSession.UseMXP = true;
		}
	}

}